package com.gzsxy.esjy.message.netty.decoder;

import com.alibaba.fastjson.JSON;
import com.gzsxy.esjy.message.channel.ChannelManager;
import com.gzsxy.esjy.message.dispatch.MessageDispatch;
import com.gzsxy.esjy.message.mds.decoder.MdsDecoder;
import com.gzsxy.esjy.message.mds.dto.MdsCoreData;
import com.gzsxy.esjy.message.mds.dto.MdsMessage;
import com.gzsxy.esjy.message.mds.encoder.MdsEncoder;
import com.gzsxy.esjy.message.mds.handler.MdsHandler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.UUID;

/**
 *  解码器 MessageToMessageDecoder 将符合条件的一种类型数据转成另一种类型数据。
 * @author zhangxiaolong
 *
 */
@Slf4j
public class HttpRequestDecoder  extends MessageToMessageDecoder<HttpRequest>{

	private final MessageDispatch messageDispatch ;

	public HttpRequestDecoder(MessageDispatch messageDispatch) {
		this.messageDispatch = messageDispatch ;
	}

	@Override
	protected void decode(ChannelHandlerContext ctx, HttpRequest request, List<Object> out) {
		//判断websocket
		if(request.method() != HttpMethod.GET) {
			UnsupportedOperationException unsupportedOperationException = new UnsupportedOperationException(String.format(
                    "method %s not supported", request.method().asciiName()));
            log.error(unsupportedOperationException.getMessage(), unsupportedOperationException);
            throw unsupportedOperationException;
		}
		//如果请求不为websocket消息，则直接返回错误信息
		if(!"websocket".equalsIgnoreCase(request.headers().get("Upgrade"))){
			UnsupportedOperationException unsupportedOperationException = new UnsupportedOperationException(String.format(
                    "missing header[Upgrade]=websocket"));
            log.error(unsupportedOperationException.getMessage(), unsupportedOperationException);
            throw unsupportedOperationException;
		}
		//获取当前访问ip
		String ip = request.headers().get("X-Real-IP");
		if(ip != null){
			//存入AttributeKey中
			ctx.channel().attr(ChannelManager.IP).set(ip);
		}else{
			ctx.channel().attr(ChannelManager.IP).set(ctx.channel().toString());
		}
		WebSocketServerHandshaker handshaker = null;
		//request.protocolVersion()请求HttpVersion.HTTP_1_1版本
		DefaultFullHttpRequest fullRequest = new DefaultFullHttpRequest(request.protocolVersion(), request.method(),
				request.uri());
		fullRequest.headers().add(request.headers());
        //构建握手响应返回，注意这条地址别被误导了，其实这里填写什么都无所谓，WS协议消息的接收不受这里控制，（websocket地址，子协议,是否允许扩展协议）
		WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(request.uri(), null, false);
		//创建一个握手处理器
		handshaker = wsFactory.newHandshaker(fullRequest);
		if (handshaker == null) {
			//不支持协议
			WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
		} else {
			//握手对象进行握手，其实就是发送响应对象
			handshaker.handshake(ctx.channel(), fullRequest);
		}
		String uri = request.uri();
		if (uri.startsWith("/mds")){
			mdsHandler(ctx.channel(),handshaker,uri) ;
		} else {
			defaultHandler(ctx.channel(),handshaker);
		}
	}


	/**
	 * 默认handler处理器
	 * @param channel
	 * @param handshaker
	 */
	private void defaultHandler(Channel channel, WebSocketServerHandshaker handshaker){
		channel.pipeline().addBefore("inner-handler","ws-decoder", new WebsocketDecoder(handshaker)) ;
	}

	/**
	 * mds
	 * @param channel
	 * @param handshaker
	 * @param uri
	 */
	private void mdsHandler(Channel channel,WebSocketServerHandshaker handshaker,String uri){
		channel.pipeline().addBefore("inner-handler","mds-decoder",new MdsDecoder(handshaker,uri))
				.addAfter("inner-handler","mds-handler",new MdsHandler(uri))
				.addLast(new MdsEncoder());

		messageDispatch.addSubscrib(uri,channel,true);
		//新增特殊转换器
		messageDispatch.addMessageConver(uri,(msg)->{
			String s = JSON.toJSONString(msg.getBody());
			MdsCoreData mdsCoreData = JSON.parseObject(s, MdsCoreData.class);
			String command = mdsCoreData.getCommand();
			MdsMessage message = new MdsMessage() ;
			message.setCommand(command);
			message.setType("request");
			message.setSessionId(UUID.randomUUID().toString());
			message.setData(s);
			log.info("推送mds {} data-before={}",command,s);
			return message ;
		});
	}

}

